local pp = require("SharedLibs.Prototype")
local co = require("SharedLibs.CoroLib")

CU = require("SharedLibs.CoUtils")
CoHelper = require("SharedLibs.CoHelper")

----------

--[[
	Switch会同时等待所有case (异步的Op, 或可转换为Op的对象), 只要任何一个case达成, 就会执行对应的handler(同步方法).
	
	是否应该增加一个 Dispatch 对象, 它可以同时监听n个Signal, 只要某个Signal触发了, 就会执行对应的异步action.
	所有action都会被放到一个map里, 如果action结束, 则从map里移除. Dispatch:Pause()时会暂停所有map里的action.

	注意: 目前Switch的每个case的handler都必须是同步执行的.
	如果要在handler里执行异步代码, 请直接在handler里执行一个新的co
]]
local cls = pp.proto();

function cls:constructor()
	self._handlerMap = {};
end

--- op可以是任意的可以被转换成AsyncOp的对象, 例如Signal
--- 最好不要传递一个常数进来, 因为会被转换成SyncOp, 导致Swtich立刻执行
function cls:Case(op, handler)
	assert(op ~= nil);
	local op = CU.ToOp(op);
	self._handlerMap[op] = handler;
	return self;
end

--- 返回值是: 返回的那个Op的返回值, 返回的那个Op
function cls:Wait()
	local map = self._handlerMap;
	local ops = {};

	for op, _ in pairs(map) do
		table.insert(ops, op);
	end

	local retVal, retOp = nil, nil;
	local internalCo = co.New(function()
		local retOp = CoHelper.WaitOneOf2(table.unpack(ops));
		local handler = self._handlerMap[retOp];

		retVal = retOp:GetReturn();
		retOp = retOp;
		handler(retVal, retOp);
	end)

	internalCo:Wait();
	return retVal, retOp;
end

return cls;
